import os

import OpenSSL
from cryptography.hazmat.primitives import serialization
from datetime import datetime as dt
from datetime import timedelta
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa

import setting


def generate_adhoc_ssl_pair(cn=None):
	pkey = rsa.generate_private_key(
		public_exponent=65537, key_size=2048, backend=default_backend()
	)

	# pretty damn sure that this is not actually accepted by anyone

	# subject：使用者
	subject = x509.Name(
		[
			x509.NameAttribute(NameOID.ORGANIZATION_NAME, setting.ON),
			x509.NameAttribute(NameOID.COMMON_NAME, setting.CN),
			x509.NameAttribute(NameOID.COUNTRY_NAME, setting.country),
		]
	)

	# issuer：颁发者
	issuer = x509.Name(
		[
			x509.NameAttribute(NameOID.ORGANIZATION_NAME, setting.ON),
			x509.NameAttribute(NameOID.COMMON_NAME, setting.CN),
			x509.NameAttribute(NameOID.COUNTRY_NAME, setting.country),
		]
	)

	# cert使用私钥签名（.sign(私钥，摘要生成算法，填充方式)），使用x509.CertificateBuilder()方法生成证书，证书属性使用下列函数叠加补充
	cert = (
		x509.CertificateBuilder()
			.subject_name(subject)
			.issuer_name(issuer)
			.public_key(pkey.public_key())
			.serial_number(x509.random_serial_number())
			.not_valid_before(dt.utcnow() + timedelta())
			.not_valid_after(dt.utcnow() + timedelta(days=1)).sign(pkey, hashes.SHA256(), default_backend())
	)
	# 最终生成的证书与密钥对为类对象，要保存在文件中还需要进一步转换成字节格式
	return cert, pkey


def ssl_init():
	if os.path.isfile(setting.ssl_cert) and os.path.isfile(setting.ssl_privateKey):
		print("SSL证书和私钥存在，初始化跳过\n")
		return

	cert, pkey = generate_adhoc_ssl_pair()
	# print(cert)
	# 将证书类对象转换成PEM格式的字节串
	cert_text = cert.public_bytes(serialization.Encoding.PEM)
	# print(cert_text)
	# 将证书字节串保存到文件中
	with open(setting.ssl_cert, mode='wb') as cert_file:
		cert_file.write(cert_text)

	# 将私钥类对象转换成PEM格式的字节串，encryption_algorithm=serialization.NoEncryption()这里是私钥不加密的意思
	private_text = pkey.private_bytes(
		encoding=serialization.Encoding.PEM,
		format=serialization.PrivateFormat.TraditionalOpenSSL,
		encryption_algorithm=serialization.NoEncryption()
	)
	# print(private_text)
	# 将私钥字节串保存到文件中
	with open(setting.ssl_privateKey, mode='wb') as pkey_file:
		pkey_file.write(private_text)
	print('SSL证书新建完毕\n')


# print("已启用自颁发的SSL/TLS加密")
# print("客户端浏览器访问时会提示 您的连接不是私密连接")


if __name__ == '__main__':
	cert, pkey = generate_adhoc_ssl_pair()
	# print(cert)
	# 将证书类对象转换成PEM格式的字节串
	cert_text = cert.public_bytes(serialization.Encoding.PEM)
	# print(cert_text)
	# 将证书字节串保存到文件中
	with open(setting.ssl_cert, mode='wb') as cert_file:
		cert_file.write(cert_text)
		cert_file.close()

	# 将私钥类对象转换成PEM格式的字节串，encryption_algorithm=serialization.NoEncryption()这里是私钥不加密的意思
	private_text = pkey.private_bytes(
		encoding=serialization.Encoding.PEM,
		format=serialization.PrivateFormat.TraditionalOpenSSL,
		encryption_algorithm=serialization.NoEncryption()
	)
	# print(private_text)
	# 将私钥字节串保存到文件中
	with open(setting.ssl_privateKey, mode='wb') as pkey_file:
		pkey_file.write(private_text)
		pkey_file.close()

	# 在程序中查看证书文件内容，当然也可以在文件夹中去双击self_signed.cer查看
	cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_text)

	certIssue = cert.get_issuer()
	print("通用名称：           ", cert.get_subject().CN)
	print("机构名：             ", cert.get_subject().O)
	print("机构单元名称：        ", cert.get_subject().OU)
	print("地理位置：            ", cert.get_subject().L)
	print("州/省名：             ", cert.get_subject().ST)
	print("国名：               ", cert.get_subject().C)
	print("证书版本:            ", cert.get_version() + 1)
	print("证书序列号:          ", hex(cert.get_serial_number()))
	print("证书中使用的签名算法: ", cert.get_signature_algorithm().decode("UTF-8"))
	print("颁发者:              ", certIssue.commonName)
	print("有效期从:             ", cert.get_notBefore())
	print("到:                   ", cert.get_notAfter())
	print("证书是否已经过期:      ", cert.has_expired())
	print("公钥长度", cert.get_pubkey().bits())
	print("公钥:\n",
	      OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey()).decode("utf-8")
	      )
	"""	
	print("主体信息:")
	print("CN : 通用名称  OU : 机构单元名称")
	print("O  : 机构名    L  : 地理位置")
	print("S  : 州/省名   C  : 国名")

	for item in certIssue.get_components():
		print(item[0].decode("utf-8"), "  ——  ", item[1].decode("utf-8"))

	print(cert.get_extension_count())
	"""
